﻿using UnityEngine;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System;
using System.Reflection;
using System.Text;

public enum VersionEnum
{
	Release,
	IC,
	PC,
	Demo,
}

public enum GamePauseEnum
{

}

public delegate void FunV();
public delegate void FunV<T>(T arg);
public delegate void FunV<T1, T2>(T1 arg1, T2 arg2);
public delegate void FunV<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void FunV<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

public delegate TResult FunR<TResult>();
public delegate TResult FunR<T, TResult>(T arg);
public delegate TResult FunR<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult FunR<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
public delegate TResult FunR<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

public class UniTool
{
	/*
	#region Pause
	
	static int s_PauseValue = 0;
	public static void PauseGame(GamePauseEnum pauseEnum)
	{
		if((s_PauseValue & 1<<(int)pauseEnum) == 0)
		{
			switch(pauseEnum)
			{

			}
		}

		bool lastPause = GameIsPause ();
		s_PauseValue = s_PauseValue | (1<<(int)pauseEnum);
		
		if(!lastPause)
		{
			UniEvent.TriggerEvent(UniEventEnum.PauseGame);
		}
	}
	
	public static void ReStartGame(GamePauseEnum pauseEnum)
	{
		if((s_PauseValue & 1<<(int)pauseEnum) != 0)
		{
			switch(pauseEnum)
			{

			}
		}

		bool lastPause = GameIsPause ();
		s_PauseValue = s_PauseValue & (~(1<<(int)pauseEnum));
		bool nowPause = GameIsPause ();
		
		if(lastPause && !nowPause)
		{
			UniEvent.TriggerEvent(UniEventEnum.ReStartGame);
		}
	}
	
	public static bool GameIsPause()
	{
		return s_PauseValue != 0;
	}
	
	public static bool CheckGamePause(GamePauseEnum pauseEnum)
	{
		return (s_PauseValue & (1<<(int)pauseEnum)) != 0;
	}
	
	#endregion
	*/

	#region Version

	static bool mVersionInit = false;
	static VersionEnum mVersion;
	public static VersionEnum Version
	{
		get
		{
			if(!mVersionInit)
			{
				Debug.LogError("Version not initialize! Please Check your code!");
			}
			return mVersion;
		}
		private set
		{
			mVersion = value;
			mVersionInit = true;
		}
	}

	public static void InitVersion(VersionEnum version)
	{
		Version = version;
	}

	#endregion

	#region File

	public static void GetChildFilePaths(string pFolderPath, ref List<string> pFileList, string pPostfix = "")
	{
		DirectoryInfo _folder = new DirectoryInfo(pFolderPath);
		if(_folder.Exists == false)
			return;
		FileInfo[] _childFiles = _folder.GetFiles();
		foreach(FileInfo item in _childFiles)
		{
			if(string.IsNullOrEmpty(pPostfix) || item.FullName.EndsWith(pPostfix))
			{
				pFileList.Add(Path.GetFileNameWithoutExtension(item.Name));
			}
		}
	}

	#endregion

	#region FloatCompare
	
	public static float FloatZero = 0.000001f;
	
	public static bool FloatIsZero(float f)
	{
		return f < FloatZero && f > -FloatZero;
	}
	
	public static bool FloatEqual(float f1, float f2 = 0)
	{
		return FloatIsZero(f1 - f2);
	}
	
	public static bool Vector3IsZero(Vector3 v)
	{
		return FloatIsZero(v.x) && FloatIsZero(v.y) && FloatIsZero(v.z);
	}
	
	#endregion
	
	#region Component
	
	public static T GetChildComponent<T>(GameObject obj, string name, bool includeInactive = false) where T: Component
	{	
		if(obj != null)
		{
			T[] tArr = obj.GetComponentsInChildren<T>(includeInactive);
			foreach(T t in tArr)
			{
				if(t.name == name)
				{
					return t;
				}
			}
		}
		
		return null;
	}

	public static List<T> GetChildsComponent<T>(GameObject obj, string name, bool includeInactive = false) where T: Component
	{	
		List<T> resArr = new List<T>();
		if(obj != null)
		{
			T[] transArr = obj.GetComponentsInChildren<T>(includeInactive);
			foreach(T t in transArr)
			{
				if(t.name == name)
				{
					resArr.Add(t);
				}
			}
		}
		
		return resArr;
	}
	
	public static T GetChildComponentByTag<T>(GameObject obj, string tag, bool includeInactive = false) where T: Component
	{
		if(obj != null)
		{
			T[] tArr = obj.GetComponentsInChildren<T>(includeInactive);
			foreach(T t in tArr)
			{
				if(t.tag == tag)
				{
					return t;
				}
			}
		}
		
		return null;
	}

	public static List<T> GetChildsComponentByTag<T>(GameObject obj, string tag, bool includeInactive = false) where T: Component
	{
		List<T> resArr = new List<T>();
		if(obj != null)
		{
			T[] transArr = obj.GetComponentsInChildren<T>(includeInactive);
			foreach(T t in transArr)
			{
				if(t.tag == tag)
				{
					resArr.Add(t);
				}
			}
		}
		
		return resArr;
	}
	
	public static GameObject GetChild(GameObject obj, string name, bool includeInactive = false)
	{
		Transform trans = GetChildComponent<Transform>(obj, name, includeInactive);
		if(trans != null)
		{
			return trans.gameObject;
		}

		return null;
	}

	public static List<GameObject> GetChilds(GameObject obj, string name, bool includeInactive = false)
	{
		List<GameObject> resArr = new List<GameObject>();
		if(obj != null)
		{
			Transform[] transArr = obj.GetComponentsInChildren<Transform>(includeInactive);
			foreach(Transform t in transArr)
			{
				if(t.name == name)
				{
					resArr.Add(t.gameObject);
				}
			}
		}
		
		return resArr;
	}

	public static GameObject GetChildByTag(GameObject obj, string tag, bool includeInactive = false)
	{
		Transform trans = GetChildComponentByTag<Transform>(obj, tag, includeInactive);
		if(trans != null)
		{
			return trans.gameObject;
		}
		
		return null;
	}
	
	public static List<GameObject> GetChildsByTag(GameObject obj, string tag, bool includeInactive = false)
	{
		List<GameObject> resArr = new List<GameObject>();
		if(obj != null)
		{
			Transform[] transArr = obj.GetComponentsInChildren<Transform>(includeInactive);
			foreach(Transform t in transArr)
			{
				if(t.tag == tag)
				{
					resArr.Add(t.gameObject);
				}
			}
		}
		
		return resArr;
	}
	
	#endregion
	
	#region String

	public static Vector2 StringToVector2(string str)
	{	
		Vector2 vec = new Vector2();
		
		string[] strArr = str.Split(',');
		float[] floatArr = {0, 0};
		
		for(int i = 0; i < strArr.Length && i < 2; i++)
		{
			float.TryParse(strArr[i], out floatArr[i]);
		}
		
		vec.x = floatArr[0];
		vec.y = floatArr[1];
		
		return vec;
	}

	public static Vector3 StringToVector3(string str)
	{	
		Vector3 vec = new Vector3();
		
		string[] strArr = str.Split(',');
		float[] floatArr = {0, 0, 0};
		
		for(int i = 0; i < strArr.Length && i < 3; i++)
		{
			float.TryParse(strArr[i], out floatArr[i]);
		}
		
		vec.x = floatArr[0];
		vec.y = floatArr[1];
		vec.z = floatArr[2];
		
		return vec;
	}

	public static Vector4 StringToVector4(string str)
	{	
		Vector4 vec = new Vector4();
		
		string[] strArr = str.Split(',');
		float[] floatArr = {0, 0, 0, 0};
		
		for(int i = 0; i < strArr.Length && i < 4; i++)
		{
			float.TryParse(strArr[i], out floatArr[i]);
		}
		
		vec.x = floatArr[0];
		vec.y = floatArr[1];
		vec.z = floatArr[2];
		vec.w = floatArr[3];

		return vec;
	}

	public static Color StringToColor(string str)
	{
		Color color = new Color();
		
		string[] strArr = str.Split(',');
		float[] floatArr = {0, 0, 0, 0};
		
		for(int i = 0; i < strArr.Length && i < 4; i++)
		{
			float.TryParse(strArr[i], out floatArr[i]);
		}
		
		color.r = floatArr[0];
		color.g = floatArr[1];
		color.b = floatArr[2];
		color.a = floatArr[3];
		
		return color;
	}

	public static Color32 StringToColor32(string str)
	{
		Color32 color = new Color32();
		
		string[] strArr = str.Split(',');
		byte[] byteArr = {0, 0, 0, 0};
		
		for(int i = 0; i < strArr.Length && i < 4; i++)
		{
			byte.TryParse(strArr[i], out byteArr[i]);
		}
		
		color.r = byteArr[0];
		color.g = byteArr[1];
		color.b = byteArr[2];
		color.a = byteArr[3];
		
		return color;
	}
	
	public static void StringSplitInt(string str, ref List<int> lst)
	{
		string[] subStr = str.Split('|');	
		foreach(string idstr in subStr)
		{
			int val;
			if(int.TryParse(idstr, out val))
			{
				lst.Add(val);
			}
		}
	}
	
	public static string StringVector3(Vector3 vec)
	{
		return "("+vec.x+" , "+vec.y+" , "+vec.z+")";
	}

	public static string StringVector2(Vector2 vec)
	{
		return "("+vec.x+" , "+vec.y+")";
	}
	
	#endregion

	#region other

	public static void ResetTrans(Transform trans)
	{
		trans.localPosition = default(Vector3);
		trans.localRotation = default(Quaternion);
		trans.localScale = new Vector3(1, 1, 1);
	}

	static int colCount;
	static int colIndex;
	public static T RandElement<T>(ICollection<T> col)
	{
		if(col.Count > 0)
		{
			colIndex = 0;
			colCount = UnityEngine.Random.Range(0, col.Count);

			foreach(T t in col)
			{
				if(colIndex == colCount)
				{
					return t;
				}
				colIndex++;
			}
		}

		return default(T);
	}

	public static T RandElement<T>(ICollection<T> col, out int outIndex)
	{
		outIndex = -1;

		if(col.Count > 0)
		{
			colIndex = 0;
			colCount = UnityEngine.Random.Range(0, col.Count);
			outIndex = colCount;
			
			foreach(T t in col)
			{
				if(colIndex == colCount)
				{
					return t;
				}
				colIndex++;
			}
		}

		return default(T);
	}

	#endregion

	#region Reflection

	public static object GetFieldValue(object src, string name)
	{
		FieldInfo info = src.GetType ().GetField (name, BindingFlags.Public |BindingFlags.NonPublic |BindingFlags.Instance);
		if(info != null)
		{
			return info.GetValue(src);
		}
		
		return null;
	}

	public static bool SetFieldValue(object src, object val, string name)
	{
		FieldInfo info = src.GetType ().GetField (name, BindingFlags.Public |BindingFlags.NonPublic |BindingFlags.Instance);
		if(info != null)
		{
			info.SetValue(src, val);
			return true;
		}

		return false;
	}

	public static bool UseMethod(object src, string name, params object[] args)
	{
		MethodInfo info = src.GetType ().GetMethod (name, BindingFlags.Public |BindingFlags.NonPublic |BindingFlags.Instance);
		if(info != null)
		{
			info.Invoke(src, args);
			return true;
		}

		return false;
	}

	#endregion

	#region IO

	public static MemoryStream StreamToMemory(Stream ins)
	{
		MemoryStream ms = new MemoryStream();
		if(ins == null && !ins.CanRead)
		{
			return ms;
		}
		
		byte[] bin = new byte[1024];
		int len;
		
		do
		{
			len = ins.Read(bin, 0, 1024);
			ms.Write(bin, 0, len);
		}
		while(len > 0);
		
		ms.Seek(0, SeekOrigin.Begin);
		return ms;
	}

	#endregion

	#region Path
	
	public static string GetResourcePath(string path)
	{
		return Application.streamingAssetsPath+"/"+path;
	}
	
	public static string GetAssetPath(string path)
	{
		if(Application.platform == RuntimePlatform.Android)
		{
			return Application.streamingAssetsPath+"/"+path;
		}
		else if(Application.platform == RuntimePlatform.IPhonePlayer)
		{
			return "file://" + Application.streamingAssetsPath+"/"+path;
		}
		
		return "file://"+Application.streamingAssetsPath+"/"+path;
	}
	
	#endregion
	
	#region Physics2D
	
	static Collider2D[] tmpCollderArr = new Collider2D[256];
	static int tmpCount;
	public static Collider2D[] OverlapCircle2D(Vector2 point, float radius)
	{
		tmpCount = Physics2D.OverlapCircleNonAlloc (point, radius, tmpCollderArr);
		Collider2D[] res = new Collider2D[tmpCount];
		Array.Copy (tmpCollderArr, res, tmpCount);
		Array.Clear (tmpCollderArr, 0, tmpCount);
		
		return res;
	}
	
	public static Collider2D[] OverlapCircle2D(Vector2 point, float radius, int layerMask)
	{
		tmpCount = Physics2D.OverlapCircleNonAlloc (point, radius, tmpCollderArr, layerMask);
		Collider2D[] res = new Collider2D[tmpCount];
		Array.Copy (tmpCollderArr, res, tmpCount);
		Array.Clear (tmpCollderArr, 0, tmpCount);
		
		return res;
	}
	
	public static Collider2D[] OverlapCircle2D(Vector2 point, float radius, int layerMask, int minDepth, int maxDepth)
	{
		tmpCount = Physics2D.OverlapCircleNonAlloc (point, radius, tmpCollderArr, layerMask, minDepth, maxDepth);
		Collider2D[] res = new Collider2D[tmpCount];
		Array.Copy (tmpCollderArr, res, tmpCount);
		Array.Clear (tmpCollderArr, 0, tmpCount);
		
		return res;
	}
	
	public static Collider2D[] OverlapArea2D(Vector2 pointA, Vector2 pointB)
	{
		tmpCount = Physics2D.OverlapAreaNonAlloc (pointA, pointB, tmpCollderArr);
		Collider2D[] res = new Collider2D[tmpCount];
		Array.Copy (tmpCollderArr, res, tmpCount);
		Array.Clear (tmpCollderArr, 0, tmpCount);
		
		return res;
	}
	
	public static Collider2D[] OverlapArea2D(Vector2 pointA, Vector2 pointB, int layerMask)
	{
		tmpCount = Physics2D.OverlapAreaNonAlloc (pointA, pointB, tmpCollderArr, layerMask);
		Collider2D[] res = new Collider2D[tmpCount];
		Array.Copy (tmpCollderArr, res, tmpCount);
		Array.Clear (tmpCollderArr, 0, tmpCount);
		
		return res;
	}
	
	public static Collider2D[] OverlapArea2D(Vector2 pointA, Vector2 pointB, int layerMask, int minDepth, int maxDepth)
	{
		tmpCount = Physics2D.OverlapAreaNonAlloc (pointA, pointB, tmpCollderArr, layerMask, minDepth, maxDepth);
		Collider2D[] res = new Collider2D[tmpCount];
		Array.Copy (tmpCollderArr, res, tmpCount);
		Array.Clear (tmpCollderArr, 0, tmpCount);
		
		return res;
	}
	
	#endregion

	#region Sprite

	public static void SetSprite(SpriteRenderer render, Sprite sprite)
	{
		if (sprite != null)
		{
			render.enabled = true;
			render.sprite = sprite;
		}
		else
		{
			render.enabled = false;
		}
	}

	#endregion

	public static T GetComponent<T>(GameObject pObj) where T : MonoBehaviour
	{
		if (pObj == null)
			return null;
		T _result = pObj.GetComponent<T>();
		if(_result == null)
			_result = pObj.AddComponent<T>();
		return _result;
	}
}
